package com.huitone.smspfm.redis.impl;

import java.net.SocketTimeoutException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.data.redis.RedisConnectionFailureException;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.ZSetOperations.TypedTuple;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bin.common.utils.StringUtils;
import com.huitone.smspfm.redis.BaseAbstractOpts;
import com.huitone.smspfm.redis.model.AppCanstant;

/**
 * 
* @Title: HashOpts.java 
* @Package com.huitone.smspfm.redis.impl 
* @Description: TODO(用一句话描述该文件做什么) 
* @author ybliang   
* @date 2017年3月15日 上午10:28:17 
* @version V1.0
 */
public class HashOpts extends BaseAbstractOpts<String, String> {
	
	private static final Logger logger = LogManager.getLogger(HashOpts.class);
	
	public void put(String key, String hashKey, String value) {
		
		long curTryTimes = 0;
		
		boolean excuteSucc = false;
		
		do {
			try {
				curTryTimes ++;
				redisTemplate.opsForHash().put(key, hashKey, value);
				excuteSucc = true;
			} catch (Exception e) {
				if (e instanceof RedisConnectionFailureException) {
					excuteSucc = false;
					logger.error("从JedisPool获取连接失败, 尝试获取连接:" + curTryTimes + "次! RedisServer:" + getMasterAddressPort());
				} else if (e instanceof SocketTimeoutException) {
					excuteSucc = true;
					logger.error("SoketTimeout,命令已经发送到Redis上执行,但是在等待执行结果的时候SocketRead超时! RedisServer:" + getMasterAddressPort(), e);
				} else {
					excuteSucc = false;
					logger.error("RedisServer:" + getMasterAddressPort(), e);
				}
			}
			
			if (!excuteSucc && (curTryTimes >= AppCanstant.MAXTRYTIMES)) {
				StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
				if (stackTrace != null) {
					StringBuffer buffer = new StringBuffer();
					for (StackTraceElement element:stackTrace) {
						buffer.append(element.getClassName() + "." + element.getMethodName() + " " + element.getLineNumber());
						buffer.append("\n");
					}
					logger.error("连续执行三次失败:\n" + buffer);
				}
				
				JSONObject json = new JSONObject();
				json.put("errorType", "redis");
				json.put("className", this.getClass().getSimpleName());
				json.put("numCnt", this.getNumCnt());
				json.put("method", "put(String key, String hashKey, String value)");
				json.put("key", key);
				json.put("hashKey", hashKey);
				json.put("value", value);
				logger.error(json.toJSONString());
				configInit.initRedis(this.getNumCnt());
			}
			
		} while (!excuteSucc && (curTryTimes < AppCanstant.MAXTRYTIMES));
		
	}
	
	public void put(String key, Map<? extends Object, ? extends Object> m) {
		
		long curTryTimes = 0;
		
		boolean excuteSucc = false;
		
		do {
			try {
				curTryTimes ++;
				redisTemplate.opsForHash().putAll(key, m);
				excuteSucc = true;
			} catch (Exception e) {
				if (e instanceof RedisConnectionFailureException) {
					excuteSucc = false;
					logger.error("从JedisPool获取连接失败, 尝试获取连接:" + curTryTimes + "次! RedisServer:" + getMasterAddressPort());
				} else if (e instanceof SocketTimeoutException) {
					excuteSucc = true;
					logger.error("SoketTimeout,命令已经发送到Redis上执行,但是在等待执行结果的时候SocketRead超时! RedisServer:" + getMasterAddressPort(), e);
				} else {
					excuteSucc = false;
					logger.error("RedisServer:" + getMasterAddressPort(), e);
				}
			}
			
			if (!excuteSucc && (curTryTimes >= AppCanstant.MAXTRYTIMES)) {
				StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
				if (stackTrace != null) {
					StringBuffer buffer = new StringBuffer();
					for (StackTraceElement element:stackTrace) {
						buffer.append(element.getClassName() + "." + element.getMethodName() + " " + element.getLineNumber());
						buffer.append("\n");
					}
					logger.error("连续执行三次失败:\n" + buffer);
				}
				JSONObject json = new JSONObject();
				json.put("errorType", "redis");
				json.put("className", this.getClass().getSimpleName());
				json.put("numCnt", this.getNumCnt());
				json.put("method", "put(String key, Map<? extends Object, ? extends Object> m)");
				json.put("key", key);
				JSONObject subJson = new JSONObject();
				for(Object obj : m.keySet()){
					subJson.put(String.valueOf(obj), m.get(obj));
				}
				json.put("map", subJson);
				logger.error(subJson.toJSONString());
				configInit.initRedis(this.getNumCnt());
				
			}
			
		} while (!excuteSucc && (curTryTimes < AppCanstant.MAXTRYTIMES));
		
	}
	
	public String get(String key, String hashKey) {
		
		long curTryTimes = 0;
		
		boolean excuteSucc = false;
		
		Object result = null;
		
		do {
			try {
				curTryTimes ++;
				result = redisTemplate.opsForHash().get(key, hashKey);
				excuteSucc = true;
			} catch (Exception e) {
				if (e instanceof RedisConnectionFailureException) {
					excuteSucc = false;
					logger.error("从JedisPool获取连接失败, 尝试获取连接:" + curTryTimes + "次! RedisServer:" + getMasterAddressPort());
				} else if (e instanceof SocketTimeoutException) {
					excuteSucc = true;
					logger.error("SoketTimeout,命令已经发送到Redis上执行,但是在等待执行结果的时候SocketRead超时! RedisServer:" + getMasterAddressPort(), e);
				} else {
					excuteSucc = false;
					logger.error("RedisServer:" + getMasterAddressPort(), e);
				}
			}
			
			if (!excuteSucc && (curTryTimes >= AppCanstant.MAXTRYTIMES)) {
				StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
				if (stackTrace != null) {
					StringBuffer buffer = new StringBuffer();
					for (StackTraceElement element:stackTrace) {
						buffer.append(element.getClassName() + "." + element.getMethodName() + " " + element.getLineNumber());
						buffer.append("\n");
					}
					logger.error("连续执行三次失败:\n" + buffer);
				}
				JSONObject json = new JSONObject();
				json.put("errorType", "redis");
				json.put("className", this.getClass().getSimpleName());
				json.put("numCnt", this.getNumCnt());
				json.put("method", "get(String key, String hashKey)");
				json.put("key", key);
				json.put("hashKey", hashKey);
				logger.error(json.toJSONString());
				configInit.initRedis(this.getNumCnt());
			}
			
		} while (!excuteSucc && (curTryTimes < AppCanstant.MAXTRYTIMES));
		
		return StringUtils.toString(result);
	}
	
	public List<Object> get(String key, Collection<Object> hashKeys) {
		
		long curTryTimes = 0;
		
		boolean excuteSucc = false;
		
		List<Object> result = new ArrayList<Object>();
		
		do {
			try {
				curTryTimes ++;
				result = redisTemplate.opsForHash().multiGet(key, hashKeys);
				excuteSucc = true;
			} catch (Exception e) {
				if (e instanceof RedisConnectionFailureException) {
					excuteSucc = false;
					logger.error("从JedisPool获取连接失败, 尝试获取连接:" + curTryTimes + "次! RedisServer:" + getMasterAddressPort());
				} else if (e instanceof SocketTimeoutException) {
					excuteSucc = true;
					logger.error("SoketTimeout,命令已经发送到Redis上执行,但是在等待执行结果的时候SocketRead超时! RedisServer:" + getMasterAddressPort(), e);
				} else {
					excuteSucc = false;
					logger.error("RedisServer:" + getMasterAddressPort(), e);
				}
			}
			
			if (!excuteSucc && (curTryTimes >= AppCanstant.MAXTRYTIMES)) {
				StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
				if (stackTrace != null) {
					StringBuffer buffer = new StringBuffer();
					for (StackTraceElement element:stackTrace) {
						buffer.append(element.getClassName() + "." + element.getMethodName() + " " + element.getLineNumber());
						buffer.append("\n");
					}
					logger.error("连续执行三次失败:\n" + buffer);
				}
				JSONObject json = new JSONObject();
				json.put("errorType", "redis");
				json.put("className", this.getClass().getSimpleName());
				json.put("numCnt", this.getNumCnt());
				json.put("method", "get(String key, Collection<Object> hashKeys)");
				json.put("key", key);
				JSONArray array = new JSONArray();
				for(Object temKey : hashKeys){
					array.add(temKey);
				}
				json.put("hashKeys", array);
				logger.error(json.toJSONString());
				configInit.initRedis(this.getNumCnt());
			}
			
		} while (!excuteSucc && (curTryTimes < AppCanstant.MAXTRYTIMES));
		
		return result;
	}
	
	public boolean hasKey(String key, String hashKey) {
		
		long curTryTimes = 0;
		
		boolean excuteSucc = false;
		
		boolean result = false;
		
		do {
			try {
				curTryTimes ++;
				result = redisTemplate.opsForHash().hasKey(key, hashKey);
				excuteSucc = true;
			} catch (Exception e) {
				if (e instanceof RedisConnectionFailureException) {
					excuteSucc = false;
					logger.error("从JedisPool获取连接失败, 尝试获取连接:" + curTryTimes + "次! RedisServer:" + getMasterAddressPort());
				} else if (e instanceof SocketTimeoutException) {
					excuteSucc = true;
					logger.error("SoketTimeout,命令已经发送到Redis上执行,但是在等待执行结果的时候SocketRead超时! RedisServer:" + getMasterAddressPort(), e);
				} else {
					excuteSucc = false;
					logger.error("RedisServer:" + getMasterAddressPort(), e);
				}
			}
			
			if (!excuteSucc && (curTryTimes >= AppCanstant.MAXTRYTIMES)) {
				StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
				if (stackTrace != null) {
					StringBuffer buffer = new StringBuffer();
					for (StackTraceElement element:stackTrace) {
						buffer.append(element.getClassName() + "." + element.getMethodName() + " " + element.getLineNumber());
						buffer.append("\n");
					}
					logger.error("连续执行三次失败:\n" + buffer);
				}
				JSONObject json = new JSONObject();
				json.put("errorType", "redis");
				json.put("className", this.getClass().getSimpleName());
				json.put("numCnt", this.getNumCnt());
				json.put("method", "hasKey(String key, String hashKey)");
				json.put("key", key);
				json.put("hashKey", hashKey);
				logger.error(json.toJSONString());
				configInit.initRedis(this.getNumCnt());
			}
			
		} while (!excuteSucc && (curTryTimes < AppCanstant.MAXTRYTIMES));
		
		return result;
	}

	public long del(String key, Object[] objects){
		
		long curTryTimes = 0;
		
		boolean excuteSucc = false;
		
		long result = 0;
		
		do {
			try {
				curTryTimes ++;
				result = redisTemplate.opsForHash().delete(key, objects);
				excuteSucc = true;
			} catch (Exception e) {
				if (e instanceof RedisConnectionFailureException) {
					excuteSucc = false;
					logger.error("从JedisPool获取连接失败, 尝试获取连接:" + curTryTimes + "次! RedisServer:" + getMasterAddressPort());
				} else if (e instanceof SocketTimeoutException) {
					excuteSucc = true;
					logger.error("SoketTimeout,命令已经发送到Redis上执行,但是在等待执行结果的时候SocketRead超时! RedisServer:" + getMasterAddressPort(), e);
				} else {
					excuteSucc = false;
					logger.error("RedisServer:" + getMasterAddressPort(), e);
				}
			}
			
			if (!excuteSucc && (curTryTimes >= AppCanstant.MAXTRYTIMES)) {
				StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
				if (stackTrace != null) {
					StringBuffer buffer = new StringBuffer();
					for (StackTraceElement element:stackTrace) {
						buffer.append(element.getClassName() + "." + element.getMethodName() + " " + element.getLineNumber());
						buffer.append("\n");
					}
					logger.error("连续执行三次失败:\n" + buffer);
				}
				JSONObject json = new JSONObject();
				json.put("errorType", "redis");
				json.put("className", this.getClass().getSimpleName());
				json.put("numCnt", this.getNumCnt());
				json.put("method", "del(String key, Object[] objects)");
				json.put("key", key);
				JSONArray array = new JSONArray();
				for(int i = 0 ; i < objects.length; i++){
					array.add(objects[i]);
				}
				json.put("hashKey", array);
				logger.error(json.toJSONString());
				configInit.initRedis(this.getNumCnt());
			}
			
		} while (!excuteSucc && (curTryTimes < AppCanstant.MAXTRYTIMES));
		
		return result;
	}
	
	public Cursor<Entry<Object, Object>> scan(String key,ScanOptions options) {

		long curTryTimes = 0;

		boolean excuteSucc = false;
		Cursor<Entry<Object, Object>> cursor = null;

		do {
			try{
				curTryTimes ++;
				cursor = redisTemplate.opsForHash().scan(key, options);
				
			} catch (Exception e) {
				if (e instanceof RedisConnectionFailureException) {
					excuteSucc = false;
					logger.error("从JedisPool获取连接失败, 尝试获取连接:" + curTryTimes + "次! RedisServer:" + getMasterAddressPort());
				} else if (e instanceof SocketTimeoutException) {
					excuteSucc = true;
					logger.error("SoketTimeout,命令已经发送到Redis上执行,但是在等待执行结果的时候SocketRead超时! RedisServer:" + getMasterAddressPort(), e);
				} else {
					excuteSucc = false;
					logger.error("RedisServer:" + getMasterAddressPort(), e);
				}
			}
			
			if (!excuteSucc && (curTryTimes >= AppCanstant.MAXTRYTIMES)) {
				StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
				if (stackTrace != null) {
					StringBuffer buffer = new StringBuffer();
					for (StackTraceElement element:stackTrace) {
						buffer.append(element.getClassName() + "." + element.getMethodName() + " " + element.getLineNumber());
						buffer.append("\n");
					}
					logger.error("连续执行三次失败:\n" + buffer);
				}
				JSONObject json = new JSONObject();
				json.put("errorType", "redis");
				json.put("className", this.getClass().getSimpleName());
				json.put("numCnt", this.getNumCnt());
				json.put("method", "scan(String key,ScanOptions options)");
				json.put("key", key);
				json.put("options", options.toOptionString());
				logger.error(json.toJSONString());
				configInit.initRedis(this.getNumCnt());
			}

		} while (!excuteSucc && (curTryTimes < AppCanstant.MAXTRYTIMES));
		
		

		return cursor;
	}
}
